Android 14 彻底终结大厂流氓应用
hi
这是 dhl
的第 90 篇文章个人微信: hi-dhl
Hi 大家好,我是 DHL,大厂程序员,就职于 美团、快手、小米。分享技术干货和编程知识点
在某些大厂内部通常都会有一个神秘的团队,他们的工作内容就是专门研究系统,而的事情就是如何让自家应用在后台存活的更久,达到永生的目的。
其中有个别公司,甚者利用公开漏洞,达到远程操控用户手机的目的,做更多他们想做的事,可以随意获取用户的隐私,而且一旦安装,普通用户很难删除,之前写了一些揭露他们的文章,但是现在已经被全部删除了,就连评论区抨击他们的内容也全都被删除了。
而 Android 14 的出现,可以说是暂时性的彻底终结了这些流氓软件,想在后台通过保活的方式,让应用在后台达到永生的目的基本不可能了。
为什么这是暂时性的呢,因为没有完美的系统,新的系统虽然修复了公开漏洞,终结了现有的保活的方式,但是新系统可能存在新的漏洞,还是会给某些大厂可乘之机。
我们一起来看一下 Android 工程副总裁 Dave Burke 都介绍 Andorid 14 在性能、隐私、安全性方面做了那些改进,这篇文章是对之前的文章 适配 Android 14,你的应用受影响了吗 和 Android 14 新增权限 的补充。
冻结缓存应用,增强杀进程能力
应用启动更快
减少内存占用
屏幕截图检查
显示全屏系统通知
精确闹钟权限
提供了对照片和视频的部分访问权限
最小 targetSdkVersion 限制
返回手势
本文只会介绍我认为 Android 14 上最大的变化,关于 Android 14 的所有变更,可以前往查看变更。https://developer.android.com/about/versions/14
冻结缓存应用,增强杀进程能力
在 Android 11 以上支持冻结已缓存的应用,当应用切换到后台并且没有其他活动时,系统会在一定时间内通过状态判断,是否冻结该应用,如果一个应用被冻结住了,将完全被 "暂停",不再消耗任何 CPU 资源,可以减少应用在后台消耗的 CPU 资源,从而达到节电的目的。
被冻结已缓存的应用并不会执行终止该应用,冻结的作用只是暂时挂起进程,消耗 CPU 的资源为 0,它有助于提高系统性能和稳定性,同时最大限度地节省设备的资源和电量的消耗,一旦应用再次切换到前台时,系统会将该应用的进程解冻,实现快速启动。
如果你的手机支持冻结已缓存的应用,在开发者选项里会显示 「暂停执行已缓存的应用」设置项。
冻结已缓存应用,在内核层面使用的是 cgroup v2 freezer,相对于使用信号 SIGSTOP 与 SIGCONT 实现的挂起与恢复,cgroup v2 freezer 无法被拦截,也就无法被开发者 Hook,从而彻底终结大厂想在这个基础上做一些事情。
当然 Google 也对 cgroup 进行了封装,提供了 Java API,在上层我们也可以调用对应的方法实现 CPU、内存资源的控制。
public static final native void setProcessFrozen(int pid, int uid, boolean frozen);public static final native void enableFreezer(boolean enable);
经过测试 Android 14 相比于 Android 13,缓存进程的 CPU 使用量降低了高达 50%,因此,除了传统的 Android 应用生命周期 API,如前台服务、JobScheduler 或 WorkManager,后台工作将受到限制。
另外在 Android 14 上系统在杀进程之前,首先会将应用所有的进程进行 cgroup v2 freezer,被冻结的应用 cpu 资源占用为 0,然后在挨个杀掉进程,想通过进程互相拉取进程的方式,不断的想通过 fork 出子进程,达到应用永生的目的,在 Android 14 以上已经不可能了,这些黑科技都要告别历史的舞台了。
应用启动更快
在 Android 14 上对缓存应用进行优化,增加了缓存应用的最大数量的限制,从而减少了冷启动应用的次数。
而应用的最大缓存数量不是固定的,可以根据设备的内存容量进行调整,Android 测试团队在 8GB 设备上,发现冷启动应用的数量减少了 20%,而在 12GB 设备上减少了超过 30%,冷启动相对于热启动来说速度较慢,而且在电量消耗方面成本较高,这一工作有效地改善了电量使用和整体应用启动时间。
减少内存占用
代码大小是我们关注的关键指标之一,代码量越大虚拟内存占用越高,减少生成的代码大小,对内存(包括 RAM 和存储空间)的影响就越小。
在 Android 14 中,改进 Android 运行时(ART)对 Android 用户体验,ART 包含了优化措施,将代码大小平均减少了 9.3%,而不会影响性能。
屏幕截图检查
在 Android 14 中新增了一个特殊的 API,截取屏幕截图后会有个 ScreenCaptureCallback
的回调,当用户正在使用截取屏幕截图时,将会调用这些回调函数。
要使 API 正常工作,需要在 AndroidManifest
中添加 DETECT_SCREEN_CAPTURE
权限,然后在 onStart()
方法中注册回调,需要在 onStop()
中取消注册。
<uses-permission android:name="android.permission.DETECT_SCREEN_CAPTURE" />
</manifest>
class MainActivity : Activity() {
private val mainExecutor = MainEcxector()
private val screenshotCallback = ScreenCaptureCallback {
// A screenshot was taken
}
override fun onStart() {
super.onStart()
registerScreenCaptureCallback(mainExecutor, screenshotCallback)
}
override fun onStop() {
super.onStop()
unregisterScreenCaptureCallback(screenshotCallback)
}
}
显示全屏系统通知
Android 11 引入了全屏通知,当全屏应用程序运行时,这些通知将在锁屏屏幕上显示,任何应用都可以在手机处于锁定状态时使用 Notification. Builder. setFullScreenIntent
发送全屏 Intent
,不过需要在 AndroidManifest
中声明 USE_FULL_SCREEN_INTENT
权限,在应用安装时自动授予此权限。
从 Android 14 开始,使用此权限的应用仅限于提供通话和闹钟的应用。对于不适合此情况的任何应用,Google Play 商店会撤消其默认的 USE_FULL_SCREEN_INTENT
权限。
在用户更新到 Android 14 之前,在手机上已经安装的应用仍拥有此权限,但是用户可以开启和关闭此权限,所以您可以使用新 API NotificationManager.canUseFullScreenIntent
检查应用是否具有该权限。
如果想在 Android 14 上使用这个权限,我们可以提示用户手动打开授权,通过 Intent(ACTION_MANAGE_APP_USE_FULL_SCREEN_INTENT)
来跳转到设置界面。
startActivity(Intent(ACTION_MANAGE_APP_USE_FULL_SCREEN_INTENT))
}
精确闹钟权限
在 Andorid 12 之前我们可以直接调用 setAlarmClock()
、setExact()
setExactAndAllowWhileIdle()
等等方法设置精确闹钟时间,
但是在 Android 12 上 Google 引入了一个新的权限 SCHEDULE_EXACT_ALARM
,如果想调用 setAlarmClock()
、setExact()
setExactAndAllowWhileIdle()
等等方法设置精确闹钟时间, 需要在 manifest
中申明 android.permission.SCHEDULE_EXACT_ALARM
权限。
所以运行在 Android 12 ~ Android 13 系统上,我们只需要声明一下权限就可以使用了,但是从 Android 14 开始 SCHEDULE_EXACT_ALARM
权限默认被禁止使用了。
如果你还想在 Andorid 14 以上使用精准闹钟的 API,我们可以提示用户手动打开授权,通过 Intent (ACTION_REQUEST_SCHEDULE_EXACT_ALARM)
来跳转到设置界面,代码如下。
when {
// If permission is granted, proceed with scheduling exact alarms.
alarmManager.canScheduleExactAlarms() -> {
alarmManager.setExact(...)
}
else -> {
// Ask users to go to exact alarm page in system settings.
startActivity(Intent(ACTION_REQUEST_SCHEDULE_EXACT_ALARM))
}
}
提供了对照片和视频的部分访问权限
这个限制和 iOS 相似,Android 14 提供了对照片和视频的部分访问权限。当您访问媒体数据时,用户将看到一个对话框,提示用户授予对所有媒体的访问、或者授予单个照片/视频的访问权限,该新功能将适用于 Android 14 上所有应用程序,无论其 targetSdkVersion
是多少。
在 Android 13 上已经引入了单独的照片访问和视频访问权限,但是在 Android 14 上新增了新的权限 READ_MEDIA_VISUAL_USER_SELECTED
。
<!-- Devices running Android 13 (API level 33) or higher -->
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
<!-- To handle the reselection within the app on Android 14 -->
<uses-permission android:name="android.permission.READ_MEDIA_VISUAL_USER_SELECTED" />
</manifest>
如果没有声明新的权限,当应用程序进入后台或用户终止应用程序时,单独的照片访问和视频访问权限将立即撤销,不会保存 READ_MEDIA_IMAGES
和 READ_MEDIA_VIDEO
权限的状态,每次都需要检查。
最小 targetSdkVersion 限制
Android 14 当中有一个比较大的变化就是,无法安装 targetSdk <= 23
的应用程序 (Android 6.0),不要将它与 minSdk
混淆。
在 Android 开发中有两个比较重要的版本号:
compileSdkVersion
:用于编译当前项目的 Android 系统版本targetSdkVersion
:App 已经适配好的系统版本,系统会根据这个版本号,来决定是否可以使用新的特性
这个最小 targetSdkVersion
限制,主要是出于安全考虑,在 Android 6.0 中引入了运行时权限机制,App 想要使用一些敏感权限时,必须先弹窗询问用户,用户点击允许之后才能使用相应的权限。
但是一些 App 为了利用权限方便获取到用户的信息,通过不去升级 targetSdk
的版本号的方式,在安装过程中获得所有权限,以最低成本的方式,绕过运行时权限机制。
如果之前已经安装了的 App,就算升级到 Android 14 也会去保留,系统不能代表用户去删除某个应用,其实我在想,为什么不针对这些已经安装好的低版本的 App,Google 给出一些警告提示,让用户可以感知到呢。
返回手势
在 Android 13 的时候,Google 已经预示我们在下一个版本中,返回手势将会有一些更新,并以预览屏幕的形式呈现动画,效果如下图所示。
我们来演示一下使用后退导航的动画。
在 Android 14 增加了在 App 中创建过渡动画的功能,比如在 OnBackPressedCallback
接口中添加了一个方法 handleonbackprogress()
,这个方法在返回手势执行过程中被调用,我们可以在这个方法中增加一些过渡动画。
在 OnBackPressedCallback
接口中还提供了两个方法 handleOnBackPressed()
和 handleOnBackCancelled()
分别在动画完成和取消动画时调用,我们来看看在代码中如何使用。
override fun onCreate(savedInstanceState: Bundle?) {
...
val box = findViewById<View>(R.id.box)
val screenWidth =
Resources.getSystem().displayMetrics.widthPixels
val maxXShift = (screenWidth / 20)
val callback = object : OnBackPressedCallback(
enabled = true
) {
override fun handleOnBackProgressed(
backEvent: BackEvent
) {
when (backEvent.swipeEdge) {
BackEvent.EDGE_LEFT ->
box.translationX = backEvent.progress *
maxXShift
BackEvent.EDGE_RIGHT ->
box.translationX = -(backEvent.progress *
maxXShift)
}
box.scaleX = 1F - (0.1F * backEvent.progress)
box.scaleY = 1F - (0.1F * backEvent.progress)
}
override fun handleOnBackPressed() {
// Back Gesture competed
}
override fun handleOnBackCancelled() {
// Back Gesture cancelled
// Reset animation objects to initial state
}
}
this.onBackPressedDispatcher.addCallback(callback)
}
}
API 被废弃
在 Android 中使用 overidePendingTransition ()
方法实现进入和退出动画,但是在 Android 14 上提供了新的 overrideActivityTransition ()
方法,而 overidePendingTransition ()
方法已被标记为弃用。
overrideActivityTransition(
enterAnim = R.anim.open_trans,
exitAnim = R.anim.exit_trans,
backgroundColor = R.color.bgr_color
)
// deprecated
overridePendingTransition(R.anim.open_trans, R.anim.exit_trans)
全文到这里就结束了,感谢你的阅读,坚持原创不易,欢迎 在看、点赞、分享 给身边的小伙伴,我会持续分享原创干货!!!
推荐阅读:
字节:成员变量,局部变量,存放在哪里,为什么局部变量需要初始化
Hi 大家好,我是 DHL,大厂程序员,就职于 美团、快手、小米。分享技术干货和编程知识点,包含性能优化、系统源码、算法、数据结构、大厂面经。
哔哩哔哩:https://space.bilibili.com/498153238
掘金:https://juejin.im/user/2594503168898744
博客:https://hi-dhl.com
Github:https://github.com/hi-dhl
👇🏻 真诚推荐你关注我👇🏻
因微信公众号更改了推送机制
可能无法及时看到最新文章
将公众号设为 星标
或常为文章点 在看
即可及时收到最新文章
欢迎前往 博客 查看更多 Kotlin、Jetpack 、动画算法图解、系统源码分析等等文章。以及开源项目、LeetCode / 剑指 offer / 国内外大厂面试题 / 多线程 题解。
https://www.hi-dhl.com